﻿/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
 * CopyRight (C) 2012-2021 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI.Common.dll can be used for free under the MIT license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UDrawing.cs
 * 文件说明: System.Drawing扩展类
 * 当前版本: V3.0
 * 创建日期: 2020-08-19
 *
 * 2021-08-19: V3.0.6 增加文件说明
******************************************************************************/

using System;
using System.Drawing;

namespace Sunny.UI
{
    public static class Drawing
    {
        public static PointF CalcAzRangePoint(this PointF center, float range, float az, float xOffset = 0, float yOffset = 0)
        {
            float x = (float)(range * 1.0f * Math.Sin(az * Math.PI / 180));
            float y = (float)(range * 1.0f * Math.Cos(az * Math.PI / 180));
            return new PointF(center.X + xOffset + x, center.Y + yOffset - y);
        }

        public static PointF CalcAzRangePoint(this Point center, float range, float az, float xOffset = 0, float yOffset = 0)
        {
            float x = (float)(range * 1.0f * Math.Sin(az * Math.PI / 180));
            float y = (float)(range * 1.0f * Math.Cos(az * Math.PI / 180));
            return new PointF(center.X + xOffset + x, center.Y + yOffset - y);
        }

        public static double CalcDistance(this PointF pt1, PointF pt2)
        {
            float xx = pt1.X - pt2.X;
            float yy = pt1.Y - pt2.Y;
            return Math.Sqrt(xx * xx + yy * yy);
        }

        public static double CalcDistance(this Point pt1, Point pt2)
        {
            int xx = pt1.X - pt2.X;
            int yy = pt1.Y - pt2.Y;
            return Math.Sqrt(xx * xx + yy * yy);
        }

        public static double CalcAngle(this Point thisPoint, Point toPoint)
        {
            double az = Math.Atan2(thisPoint.Y - toPoint.Y, thisPoint.X - toPoint.X) * 180 / Math.PI;
            az = (az - 270 + 720) % 360;
            return az;
        }

        public static double CalcAngle(this PointF thisPoint, PointF toPoint)
        {
            double az = Math.Atan2(thisPoint.Y - toPoint.Y, thisPoint.X - toPoint.X) * 180 / Math.PI;
            az = (az - 270 + 720) % 360;
            return az;
        }

        public static PointF Center(this Rectangle rect)
        {
            return new PointF(rect.Left + rect.Width / 2.0f, rect.Top + rect.Height / 2.0f);
        }

        public static PointF Center(this RectangleF rect)
        {
            return new PointF(rect.Left + rect.Width / 2.0f, rect.Top + rect.Height / 2.0f);
        }

        public static Color Alpha(this Color color, int alpha)
        {
            alpha = Math.Max(0, alpha);
            alpha = Math.Min(255, alpha);
            return Color.FromArgb(alpha, color);
        }

        public static bool InRect(this Point point, Rectangle rect)
        {
            return point.X >= rect.Left && point.X <= rect.Right && point.Y >= rect.Top && point.Y <= rect.Bottom;
        }

        public static bool InRect(this Point point, RectangleF rect)
        {
            return point.X >= rect.Left && point.X <= rect.Right && point.Y >= rect.Top && point.Y <= rect.Bottom;
        }

        public static bool InRect(this PointF point, Rectangle rect)
        {
            return point.X >= rect.Left && point.X <= rect.Right && point.Y >= rect.Top && point.Y <= rect.Bottom;
        }

        public static bool InRect(this PointF point, RectangleF rect)
        {
            return point.X >= rect.Left && point.X <= rect.Right && point.Y >= rect.Top && point.Y <= rect.Bottom;
        }

        /// <summary>
        /// 两个矩阵是否重叠（边沿重叠，也认为是重叠）
        /// </summary>
        /// <param name="rc1">第一个矩阵的位置</param>
        /// <param name="rc2">第二个矩阵的位置</param>
        /// <returns></returns>
        public static bool IsOverlap(this Rectangle rc1, Rectangle rc2)
        {
            return rc1.X + rc1.Width > rc2.X &&
                   rc2.X + rc2.Width > rc1.X &&
                   rc1.Y + rc1.Height > rc2.Y &&
                   rc2.Y + rc2.Height > rc1.Y;
        }


        /// <summary>
        /// 两个矩阵是否重叠（边沿重叠，也认为是重叠）
        /// </summary>
        /// <param name="rc1">第一个矩阵的位置</param>
        /// <param name="rc2">第二个矩阵的位置</param>
        /// <returns></returns>
        public static bool IsOverlap(this RectangleF rc1, RectangleF rc2)
        {
            return rc1.X + rc1.Width > rc2.X &&
                   rc2.X + rc2.Width > rc1.X &&
                   rc1.Y + rc1.Height > rc2.Y &&
                   rc2.Y + rc2.Height > rc1.Y;
        }

        /// <summary>
        /// 两点创建一个矩形
        /// </summary>
        /// <param name="pf1">点1</param>
        /// <param name="pf2">点2</param>
        /// <returns>矩形</returns>
        public static RectangleF CreateRectangleF(this PointF pf1, PointF pf2)
        {
            return new RectangleF(Math.Min(pf1.X, pf2.X), Math.Min(pf1.Y, pf2.Y),
                Math.Abs(pf1.X - pf2.X), Math.Abs(pf1.Y - pf2.Y));
        }

        /// <summary>
        /// 两点创建一个矩形
        /// </summary>
        /// <param name="pf1">点1</param>
        /// <param name="pf2">点2</param>
        /// <returns>矩形</returns>
        public static Rectangle CreateRectangle(this Point pf1, Point pf2)
        {
            return new Rectangle(Math.Min(pf1.X, pf2.X), Math.Min(pf1.Y, pf2.Y),
                Math.Abs(pf1.X - pf2.X), Math.Abs(pf1.Y - pf2.Y));
        }


        public static double CalcY(this PointF pf1, PointF pf2, double x)
        {
            if (pf1.Y.Equals(pf2.Y)) return pf1.Y;
            if (pf1.X.Equals(pf2.X)) return float.NaN;

            double a = (pf2.Y - pf1.Y) * 1.0 / (pf2.X - pf1.X);
            double b = pf1.Y - a * pf1.X;
            return a * x + b;
        }

        public static double CalcX(this PointF pf1, PointF pf2, double y)
        {
            if (pf1.X.Equals(pf2.X)) return pf1.X;
            if (pf1.Y.Equals(pf2.Y)) return float.NaN;

            double a = (pf2.Y - pf1.Y) * 1.0 / (pf2.X - pf1.X);
            double b = pf1.Y - a * pf1.X;
            return (y - b) * 1.0 / a;
        }

        public static double CalcY(this Point pf1, Point pf2, double x)
        {
            if (pf1.Y == pf2.Y) return pf1.Y;
            if (pf1.X == pf2.X) return double.NaN;

            double a = (pf2.Y - pf1.Y) * 1.0 / (pf2.X - pf1.X);
            double b = pf1.Y - a * pf1.X;
            return a * x + b;
        }

        public static double CalcX(this Point pf1, Point pf2, double y)
        {
            if (pf1.Y == pf2.Y) return pf1.X;
            if (pf1.X == pf2.X) return double.NaN;

            double a = (pf2.Y - pf1.Y) * 1.0 / (pf2.X - pf1.X);
            double b = pf1.Y - a * pf1.X;
            return (y - b) * 1.0 / a;
        }

        /// <summary>
        /// 设置递进颜色
        /// </summary>
        /// <param name="color">颜色</param>
        /// <param name="alpha">alpha</param>
        /// <returns>颜色</returns>
        public static Color StepColor(this Color color, int alpha)
        {
            if (alpha == 100)
            {
                return color;
            }

            byte a = color.A;
            byte r = color.R;
            byte g = color.G;
            byte b = color.B;
            float bg;

            int _alpha = Math.Max(alpha, 0);
            double d = (_alpha - 100.0) / 100.0;

            if (d > 100)
            {
                // blend with white
                bg = 255.0F;
                d = 1.0F - d;  // 0 = transparent fg; 1 = opaque fg
            }
            else
            {
                // blend with black
                bg = 0.0F;
                d = 1.0F + d;  // 0 = transparent fg; 1 = opaque fg
            }

            r = (byte)(BlendColor(r, bg, d));
            g = (byte)(BlendColor(g, bg, d));
            b = (byte)(BlendColor(b, bg, d));

            return Color.FromArgb(a, r, g, b);
        }

        private static double BlendColor(double fg, double bg, double alpha)
        {
            double result = bg + (alpha * (fg - bg));
            if (result < 0.0)
            {
                result = 0.0;
            }

            if (result > 255)
            {
                result = 255;
            }

            return result;
        }

        public static bool IsNullOrEmpty(this Color color)
        {
            return color == Color.Empty || color == Color.Transparent;
        }

        public static bool IsValid(this Color color)
        {
            return !color.IsNullOrEmpty();
        }

        /// <summary>
        /// 平移
        /// </summary>
        public static Point Offset(this Point point, Size size)
        {
            point.Offset(size.Width, size.Height);
            return point;
        }

        /// <summary>
        /// 宽度放大
        /// </summary>
        public static Size MultiplyWidth(this Size size, int multiple)
        {
            return new Size(size.Width * multiple, size.Height);
        }

        /// <summary>
        /// 高度放大
        /// </summary>
        public static Size MultiplyHeight(this Size size, int multiple)
        {
            return new Size(size.Width, size.Height * multiple);
        }

        /// <summary>
        /// 宽度和高度放大
        /// </summary>
        public static Size MultiplyAll(this Size size, int multiple)
        {
            return new Size(size.Width * multiple, size.Height * multiple);
        }

        /// <summary>
        /// 宽度放大
        /// </summary>
        public static Size MultiplyWidth(this Size size, double multiple)
        {
            return new Size((int)(size.Width * multiple), size.Height);
        }

        /// <summary>
        /// 高度放大
        /// </summary>
        public static Size MultiplyHeight(this Size size, double multiple)
        {
            return new Size(size.Width, (int)(size.Height * multiple));
        }

        /// <summary>
        /// 宽度和高度放大
        /// </summary>
        public static Size MultiplyAll(this Size size, double multiple)
        {
            return new Size((int)(size.Width * multiple), (int)(size.Height * multiple));
        }

        /// <summary>
        /// 区域是否可见
        /// </summary>
        public static bool IsVisible(this Rectangle rect)
        {
            return rect.Width > 0 && rect.Height > 0;
        }

        public static Color RandomColor()
        {
            Random random = new Random();
            return Color.FromArgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
        }

        public static Color MixColors(this Color[] colors)
        {
            var r = default(int);
            var g = default(int);
            var b = default(int);
            foreach (var c in colors)
            {
                r += c.R;
                g += c.B;
                b += c.B;
            }
            return Color.FromArgb(r / colors.Length, g / colors.Length, b / colors.Length);
        }
    }
}
